#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#include "opencv2/opencv.hpp"

#include "ImageProcessingLib.hpp"
#include "opencv2/objdetect.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"

#include <opencv2/tracking.hpp>
#include <opencv2/core/ocl.hpp>
//#define min(a,b) (a)<(b)?(a):(b)


void callback(char*, int);
 
int readline_sock(int sockfd,char* RecvData,int RecvLen)
{
	char tmp;
	int len = 0;
	int ret;
	while(len < RecvLen && (ret = recv(sockfd,&tmp,1,0)) == 1)
	{
		if(tmp == '\r')
			break;
		memcpy(RecvData + len,&tmp,1);
		len += 1;
	}
	if(ret != 1)
	{
		printf("readline err %d %s",errno,strerror(errno));
		return -1;
	}
	if(len == RecvLen)
		return len;
	if(tmp == '\r')
	{
		ret = recv(sockfd,&tmp,1,0);
		if(ret != 1)
		{
			printf("readline err %d %s",errno,strerror(errno));
			return -1;
		}
		else
		{
			return len;
		}
	}
}

int readbytes_sock(int sockfd,char* RecvData,int RecvLen)
{
	int len = 0,l = 0;

	while((len = recv(sockfd,RecvData + l,RecvLen - l,0)) > 0)
	{
		l += len;
	}
	if(len < 0)
		return len;
	return l;
}
 
 
int connect_alipay_new(char *host,int port,char *sendData,int sendData_len,char *recvData,int recvData_maxlen)
{
	int sockfd;
	struct hostent *phost = NULL;
	struct sockaddr_in sin;
	char tmp[0x8000 + 1];
	int tmp_len = 0;
	char name[100],value[100],*index1,*index2;
	
	int fd = 0;
	int recv_len = 0 ,len,len2;
	
	
	printf("gethostbyname start %s\n",__TIME__);
	phost = gethostbyname(host);
	if(phost ==NULL)	return 1;
	
	sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	printf("gethostbyname end ok %s\n",__TIME__);
	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);
	sin.sin_addr = *(struct in_addr*)phost->h_addr_list[0];
	
	printf("connect start %s\n",__TIME__);
	if(connect(sockfd,(struct sockaddr*)&sin,sizeof(sin)) < 0)
	{
		printf("connect err [%d] [%s]\n",errno,strerror(errno));
		exit(0);
	}
	printf("connect end ok %s\n",__TIME__);
	
	
	send(sockfd,sendData,sendData_len,0);
	
	memset(recvData,0,recvData_maxlen);
	
	memset(tmp,0,sizeof(tmp));
	tmp_len = readline_sock(sockfd,tmp,sizeof(tmp));
	if(tmp_len == -1)	return tmp_len;
	if(memcmp(tmp,"HTTP/1.1 200",12) != 0)
	{
		//recv_len = -1;
		//goto finish;
	}
	
	do
	{
		memset(tmp,0,sizeof(tmp));
		
		tmp_len = readline_sock(sockfd,tmp,sizeof(tmp));
		printf("lllll[%d][%s]\n",tmp_len,tmp);
		if(tmp_len <= 0)break;
		memset(name,0,sizeof(name));
		memset(value,0,sizeof(value));
		index1 = strchr(tmp,':');
		if(index1 == NULL)	break;
		strncpy(name,tmp,index1 - tmp);
		if(*(index1+1) == ' ')	index1++;
		strcpy(value,index1);
		printf("name:[%s] value[%s]\n",name,value);
		setenv(name,value,1);
	}while(1);
	
	memset(recvData,0,recvData_maxlen);
	
	
	if(tmp_len < 0)	
	{
		recv_len = -1;
		goto finish;
	}
	
	fd = open("log2",O_WRONLY|O_CREAT,0664);
	
	index1 = NULL;
	index1 = getenv("Transfer-Encoding");
	if(index1 != NULL)
	{
		recv_len = 0;
		while(1)
		{
			memset(tmp,0,sizeof(tmp));
			tmp_len = readline_sock(sockfd,tmp,sizeof(tmp));
			if(tmp_len == 0)
			{
				recv_len = -1;
				goto finish;
			}
			len = 0;
			sscanf(tmp,"%x",&len);
			
//			printf("len:[%d]\ndata:[%s]",len,tmp);
			
			if(len == 0)
			{
				printf("finish\n");
				break;
			}
			memset(tmp,0,sizeof(tmp));
			tmp_len = 0;
			tmp_len = readbytes_sock(sockfd,tmp,len);
			if(tmp_len != len || tmp_len < 0)
			{
				printf("tmp_len != len,tmp_len=[%d] len=[%d]\n",tmp_len,len);
				recv_len = -1;
				goto finish;
			}
			else
			{
				write(fd,tmp,len);
				//memcpy(recvData + recv_len,tmp,len);
				recv_len += len;
			}
			tmp_len = readline_sock(sockfd,tmp,sizeof(tmp));
			if(tmp_len == 0)
				continue;
			else
				break;
		}
		goto finish;
	}
	
	index1 = NULL;
	index1 = getenv("Content-Length");
	if(index1 != NULL)
	{
		len = atol(index1);
		printf("Content-Lenght[%d]\n",len);
		if(len >= recvData_maxlen)
		{
			recv_len = -1;
			goto finish;
		}
		else
		{
			recv_len = readbytes_sock(sockfd,recvData,len);
			if(recv_len < len)
			{
				recv_len = -1;
				goto finish;
			}
			goto finish;
		}
	}
	
 
finish:
 
	close(sockfd);
 
	return recv_len;
	
}
 
int connect_alipay_fd(const char *host,int port,char *sendData,int sendData_len,int fd)
{
	int sockfd;
	struct hostent *phost = nullptr;
	struct sockaddr_in sin{};
	char tmp[0x8000 + 1];
	int tmp_len = 0;
	char name[100],value[100],*index1,*index2;
 
	int recv_len = 0 ,len,len2;


	printf("gethostbyname start %s\n",__TIME__);
	phost = gethostbyname(host);
	if(phost ==NULL)	return 1;
	
	sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	printf("gethostbyname end ok %s\n",__TIME__);
	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);
	sin.sin_addr = *(struct in_addr*)phost->h_addr_list[0];
	
	printf("connect start %s\n",__TIME__);
	if(connect(sockfd,(struct sockaddr*)&sin,sizeof(sin)) < 0)
	{
		printf("connect err [%d] [%s]\n",errno,strerror(errno));
		exit(0);
	}
	printf("connect end ok %s\n",__TIME__);
	
	
	send(sockfd,sendData,sendData_len,0);
	
	
	memset(tmp,0,sizeof(tmp));
	tmp_len = readline_sock(sockfd,tmp,sizeof(tmp));
	if(tmp_len == -1)	return tmp_len;
	if(memcmp(tmp,"HTTP/1.1 200",12) != 0)
	{
		//recv_len = -1;
		//goto finish;
	}

	do
	{
		memset(tmp,0,sizeof(tmp));
		
		tmp_len = readline_sock(sockfd,tmp,sizeof(tmp));
		printf("lllll[%d][%s]\n",tmp_len,tmp);
		if(tmp_len <= 0)break;
		memset(name,0,sizeof(name));
		memset(value,0,sizeof(value));
		index1 = strchr(tmp,':');
		if(index1 == NULL)	break;
		strncpy(name,tmp,index1 - tmp);
		if(*(index1+1) == ' ')	index1+=2;
		else index1 +=1;
		strcpy(value,index1);
		printf("name:[%s] value[%s]\n",name,value);
		setenv(name,value,1);
	}while(1);
	
	
	
	
	if(tmp_len < 0)	
	{
		recv_len = -1;
		goto finish;
	}
	
	
	index1 = NULL;
	index1 = getenv("Transfer-Encoding");
	if(index1 != NULL && strcmp(index1,"chunked") == 0)
	{
		recv_len = 0;
		while(1)
		{
			memset(tmp,0,sizeof(tmp));
			tmp_len = readline_sock(sockfd,tmp,sizeof(tmp));
			if(tmp_len == 0)
			{
				recv_len = -1;
				goto finish;
			}
			len = 0;
			sscanf(tmp,"%x",&len);

//			printf("len:[%d]\ndata:[%s]",len,tmp);
			
			if(len == 0)
			{
				printf("finish\n");
				break;
			}
			memset(tmp,0,sizeof(tmp));
			tmp_len = 0;
			tmp_len = readbytes_sock(sockfd,tmp,len);
			if(tmp_len != len || tmp_len < 0)
			{
				printf("tmp_len != len,tmp_len=[%d] len=[%d]\n",tmp_len,len);
				recv_len = -1;
				goto finish;
			}
			else
			{
                callback(tmp,len);
//				write(fd,tmp,len);
			}
			tmp_len = readline_sock(sockfd,tmp,sizeof(tmp));
			if(tmp_len == 0)
				continue;
			else
				break;
		}
		goto finish;
	}
	
	index1 = NULL;
	index1 = getenv("Content-Length");
	if(index1 != NULL)
	{
		len = atol(index1);
		printf("Content-Lenght[%d]\n",len);
		recv_len = 0;
		while(recv_len < len) {
            memset(tmp, 0, sizeof(tmp));
            auto length_ = sizeof(tmp) - 1;
            if ((len - recv_len) < (sizeof(tmp) - 1)) {
                length_ = (len - recv_len);
            }
            tmp_len = readbytes_sock(sockfd, tmp, length_);
            if (tmp_len < 0) {
                recv_len = -1;
                goto finish;
            }
            recv_len += tmp_len;
//			write(fd,tmp,tmp_len);
            callback(tmp,len);
        }

        goto finish;
 
	}
	
 
finish:
 
	close(sockfd);

	return recv_len;

}

cv::Mat char_to_mat(char *image_buf, int image_len){
    cv::Mat mat;
    std::string str2(image_buf, image_len);
    std::vector<char> vec_data1(str2.c_str(), str2.c_str() + str2.size());
    mat = cv::imdecode(vec_data1, -1).clone();
    return mat;
}


static std::string faceData = "/home/monoliths/Documents/Project/OpenCV/TestHumenFaceReconous/cascades/haarcascade_frontalface_default.xml";

bool faceDetected = false;

auto faceCascade = new cv::CascadeClassifier(faceData);

auto faceTracker = cv::TrackerKCF::create();

void callback(char* data_, int length_)
{
    if (length_ > 100)
    {
//        std::cout << "rcv" << length_ << std::endl;
//        cv::Mat mat(1280, 720, 16);
//        cv::Mat mat(1280, 720, 16, (void*) data_);
//        cv::imshow("window", mat);
        //读取
//        fIn.read((char*)YUVFrameBuff, size*sizeof(unsigned char));
//        memcpy(mat.data,reinterpret_cast<unsigned char *>(data_), length_ * sizeof(unsigned char));
//        cv::Mat bgrImg;
//        cv::cvtColor(mat, bgrImg, cv::COLOR_RGB2BGR);
//        cv::namedWindow("bgrImg");
        auto res = char_to_mat(data_, length_);
        cv::Mat gray;
        cvtColor(res, gray, cv::ColorConversionCodes::COLOR_BGR2GRAY);

        std::vector<cv::Rect> facesPostion;
        faceCascade->detectMultiScale(gray, facesPostion, 1.3, 5);

        // std::vector<Rect> eyesPosition;
        // eyesCascade->detectMultiScale(gray, eyesPosition, 1.3, 5);
        // std::vector<Rect> upBodyPosition;
        // upBodyCascade->detectMultiScale(gray, upBodyPosition, 1.3, 5);

        cv::Rect face;
        if (!faceDetected && !facesPostion.empty())
        {
            faceTracker->init(res, facesPostion[0]);
            faceDetected = true;
        }

        if (faceDetected && faceTracker->update(res, face))
        {
            rectangle(res, face, cv::Scalar(0, 0, 255), 2);
        }

        cv::imshow("bgrImg", res);
        cv::waitKey(10);
    }
}
